package com.polaris.live.manager

import com.blankj.utilcode.util.GsonUtils
import com.google.common.cache.CacheBuilder
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.ktx.Firebase
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.constant.ServerConfig
import com.polaris.live.common.network.EncryptHelper
import com.polaris.live.common.resp.ConfigPostResp
import com.polaris.live.common.resp.ConfigPreResp
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.resp.back_resp.UserRoomThemeResp
import com.polaris.live.resp.event.ConfigInitializedEvent
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.TimeUnit

/**
 * AppConfigManager
 *
 * @author Created by lucas on 2023/10/25 20:57
 */
object AppConfigManager {

    @Volatile
    private var configPreResp: ConfigPreResp? = null

    @Volatile
    private var configPostResp: ConfigPostResp? = null

    @Volatile
    private var secretMap: Map<String, String>? = null

    @Volatile
    private var configMap: Map<String, String>? = null

    @Volatile
    private var configInitialized: Boolean = false

    private const val CONFIG_PRE_LOCK = "CONFIG_PRE_LOCK"
    private const val CONFIG_POST_LOCK = "CONFIG_POST_LOCK"
    private const val CONFIG_MAP_LOCK = "CONFIG_MAP_LOCK"
    private const val SECRET_MAP_LOCK = "SECRET_MAP_LOCK"

    /**
     * 获取应用配置
     */
    fun getConfig(key: String): String? {
        return getConfigMap()?.get(key)
    }

    /**
     * 获取所有的应用配置
     */
    fun getConfigMap(): Map<String, String>? {
        if (isConfigInitialized()) {
            return configMap
        }

        return synchronized(CONFIG_MAP_LOCK) {
            if (isConfigInitialized()) {
                configMap
            } else {
                invokeGetConfigMap().apply {
                    configMap = this
                }
            }
        }
    }

    fun isConfigInitialized() = configMap != null && configInitialized

    private fun invokeGetConfigMap(): Map<String, String>? {
        val configPre = getConfigPre()
        return if (configPre == null) {
            null
        } else {
            val secret = configPre.configs?.get(CommonConst.Configs.secret)
            val secretMap = resolveSecretMap(secret)

            val preMap = (configPre.configs ?: emptyMap()) + (secretMap ?: emptyMap())

            val configPost = getConfigPost()
            if (configPost == null) {
                preMap
            } else {
                val map = preMap + (configPost.configs ?: emptyMap())
                map.apply {
                    configInitialized = true
                }
            }
        }
    }

    private fun resolveSecretMap(secret: String?): Map<String, String>? {
        return secretMap ?: synchronized(SECRET_MAP_LOCK) {
            secretMap ?: let {
                invokeResolveSecretMap(secret).apply {
                    secretMap = this
                }
            }
        }
    }

    private fun invokeResolveSecretMap(secret: String?): Map<String, String>? {
        if (secret == null) {
            return null
        }
        val decryptStr = EncryptHelper.decrypt(secret, ServerConfig.getServerMode().secEncrypt)
            ?: return null

        return JsonUtils.fromJson<Map<String, String>>(decryptStr)
    }

    /**
     * 获取pre配置
     */
    fun getConfigPre(): ConfigPreResp? {
        return configPreResp ?: synchronized(CONFIG_PRE_LOCK) {
            configPreResp ?: let {
                val configPre = CacheUtil.getConfigPreFromKV()

                configPre.apply {
                    configPreResp = this
                }
            }
        }
    }

    fun updateConfigPre(configPre: ConfigPreResp) {
        configPreResp = configPre

        CacheUtil.saveConfigPre(configPre)

        configMap = null
    }

    /**
     * 获取post配置
     */
    fun getConfigPost(): ConfigPostResp? {
        return configPostResp ?: synchronized(CONFIG_POST_LOCK) {
            configPostResp ?: let {
                val configPost = CacheUtil.getConfigPostFromKV()

                configPost.apply {
                    configPostResp = this
                }
            }
        }
    }

    fun updateConfigPost(configPost: ConfigPostResp) {
        val newConfigPost = if (configPost.configs.isNullOrEmpty()) {
            //有可能存在本地已经有数据的情况下，不覆盖本地配置
            val oldConfigPost = getConfigPost()
            if (oldConfigPost != null) {
                configPost.copy(
                    configs = oldConfigPost.configs
                )
            } else {
                configPost
            }
        } else {
            configPost
        }

        configPostResp = newConfigPost

        configMap = null

        CacheUtil.saveConfigPost(newConfigPost)

        newConfigPost.configVersion?.also {
            CacheUtil.saveConfigVersion(it)
        }

        CacheUtil.setUniqueId(newConfigPost.uniqueId)

        DomainManager.asyncFetchIpCountry(newConfigPost.uniqueId)
        AdJustManager.uploadAdJust(null, newConfigPost.uniqueId)

        FirebaseCrashlytics.getInstance().setCustomKey("uniqueId", newConfigPost.uniqueId)
        Firebase.analytics.setUserProperty("uniqueId", newConfigPost.uniqueId)

        //发送初始化完成事件
        EventBus.getDefault().post(ConfigInitializedEvent(configPost))
    }

    private val mThemeCache = CacheBuilder.newBuilder()
        .maximumSize(10)
        .expireAfterAccess(10, TimeUnit.MINUTES)
        .build<String, UserRoomThemeResp>()

    /**
     * 获取主题数据
     */
    fun getUserTheme(theme: String? = null): UserRoomThemeResp? {
        if (theme.isNullOrBlank()) {
            return null
        }

        val res = mThemeCache.get(theme) {
            val jsonConfig = getConfig(CommonConst.Configs.roomSkin)
                ?: return@get UserRoomThemeResp.EMPTY

            val jsonObject = JsonParser.parseString(jsonConfig)
            if (jsonObject !is JsonObject) {
                return@get UserRoomThemeResp.EMPTY
            }

            val element = jsonObject.get(theme)
                ?: return@get UserRoomThemeResp.EMPTY

            GsonUtils.getGson().fromJson(element, UserRoomThemeResp::class.java)
        }

        return if (res.isEmpty()) {
            null
        } else {
            res
        }
    }
}